package com.xhu.collegestudentrentalsystem.module.user.controller;
import com.google.code.kaptcha.Producer;
import com.xhu.collegestudentrentalsystem.module.user.entity.User;
import com.xhu.collegestudentrentalsystem.module.user.service.impl.UserServiceImpl;
import com.xhu.collegestudentrentalsystem.util.*;
import com.xhu.collegestudentrentalsystem.util.constant.EntityProperty;
import com.xhu.collegestudentrentalsystem.util.constant.EnumProperty;
import com.xhu.collegestudentrentalsystem.util.constant.KeyMsg;
import com.xhu.collegestudentrentalsystem.util.constant.PointMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

/**
 * @author zhu huilin
 * @date 2023/2/26 11:05
 */
@RestController
public class LoginController {

    // 利用工厂得到日志对象，统一书写日志
    private static final Logger logger= LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private UserServiceImpl userService;

    @Autowired
    private CacheUtils cacheUtils;

    @Autowired
    private MailClient mailClient;

    @Autowired
    private Producer kaptchaProducer;

    @Autowired
    private JWTUtils jwtUtils;

    @Autowired
    private HostHolder hostHolder;

    /**
     * 1、用户注册：此时用户只需要邮箱验证，详细信息需在个人页面进行补充
     */
    @PostMapping("/register")
    public ResultData register(User user, String emailCode){
        // 填充创建时间
        user.setCreateTime(new Date());
        // 从缓存中取出邮箱验证码信息，进行验证
        String code = cacheUtils.getLocalCache().getIfPresent(user.getEmail());
        if(!code.equals(emailCode)){
            return new ResultData(ResultData.OPERATION_FAIL, PointMsg.register.ERROR_EMAIL_CODE);
        }
        // 验证通过，向数据库中插入数据
        return userService.register(user);
    }

    /**
     * 1.1 检测用户邮箱是否在数据库中存在
     */
    @RequestMapping("/checkEmail")
    public ResultData checkData(String email){
        ResultData resultData = new ResultData();
        // 查询数据库是否存在邮箱信息
        if(userService.isEmailExist(email)){
            resultData.put(KeyMsg.CODE, ResultData.DATA_EXIST);
            resultData.put(KeyMsg.MSG, PointMsg.register.EXIST_EMAIL);
        }else {
            resultData.put(KeyMsg.CODE, ResultData.DATA_UNEXIST);
        }
        return resultData;
    }

    /**
     * 1.2 验证是否有重名用户
     */
    @RequestMapping("/checkUsername")
    public ResultData checkUsername(String username){
        if(userService.isUsernameExist(username)){
            return new ResultData(ResultData.OPERATION_FAIL, PointMsg.register.EXIST_USERNAME);
        }
        return new ResultData(ResultData.OPERATION_SUCCESS, PointMsg.register.NONE);
    }

    /**
     * 1.2 发送邮箱验证码
     */
    @RequestMapping("/sendEmailCode")
    public ResultData sendEmailCode(String email) throws MessagingException {
        // 随机生成四位数验证码
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < 4; i++) {
            sb.append(random.nextInt(10));
        }
        cacheUtils.getLocalCache().put(email, sb.toString());
        mailClient.sendMail(email, "验证码", "您的验证码是：" + sb.toString() + " 两分钟内有效，请尽快验证。");
        return new ResultData(ResultData.OPERATION_SUCCESS, "验证码发送成功，有效期为2分钟");
    }


    /**
     * 2、用户使用密码登录（如果要加Spring Security则不需要该路径，重新将验证码、用户认证逻辑在handler中实现）
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ModelAndView login(String userName, String userPass, String role, String codeMsg, boolean rememberme, HttpServletRequest request, HttpServletResponse response){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("site/login");
        //获取ip
        String remoteAddr = request.getRemoteAddr();
        // 从前端的cookies中得到标识，再从localCache中获取验证码
        String kaptcha = null;
        String uuid = null;
        Cookie[] cookies = request.getCookies();
        if (cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (KeyMsg.CAPTCHA.equals(cookie.getName())) {
                    uuid = cookie.getValue();
                    kaptcha = cacheUtils.getLocalCache().getIfPresent(uuid);
                    break;
                }
            }
        }

        if(kaptcha == null){    // 验证码过期
            mv.addObject(KeyMsg.CODE_MSG, PointMsg.login.VERIFY_CODE_EXPIRED);
            return mv;
        }
        if(!kaptcha.equalsIgnoreCase(codeMsg)){     // 验证码错误
            mv.addObject(KeyMsg.CODE_MSG, PointMsg.login.ERROR_VERIFY_CODE);
            return mv;
        }
        // 验证码正确，将缓存中的验证码删除
        cacheUtils.getLocalCache().invalidate(uuid);

        // 验证用户密码
        ResultData resultData = userService.verifyUser(userName, userPass, role);
        Integer statusCode = Integer.valueOf(resultData.get(KeyMsg.CODE).toString());
        if(statusCode == ResultData.LOGIN_FAIL){
            mv.addObject(KeyMsg.user.LOGIN_PASS_MSG, resultData.get(KeyMsg.MSG).toString());
        }else if(statusCode == ResultData.OPERATION_FAIL) {
            mv.addObject(KeyMsg.user.LOGIN_USER_MSG, resultData.get(KeyMsg.MSG).toString());
        }

        if(resultData.get(KeyMsg.CODE).equals(ResultData.LOGIN_SUCCESS)){
            // 登录成功将信息存入JWT，发送给前端，前端再次发送请求后，从中取出数据存入hostHolder
            // hostHolder.setUser((User) resultData.get("data"));
            // 封装信息，用于生成JWT
            User user = (User)resultData.get(KeyMsg.DATA);
            Map<String, Object> payloadInfo = new HashMap<>();
            payloadInfo.put(EntityProperty.user.USERNAME, user.getUsername());
            payloadInfo.put(EntityProperty.user.USER_ROLE, user.getRole());
            payloadInfo.put(EntityProperty.user.USER_EMAIL, user.getEmail());

            // 生成token（如果勾选了，登录页面“记住我”功能，则保存时间设置为24h）
            String token = jwtUtils.createToken(payloadInfo, rememberme? EnumProperty.REMEMBER_EXPIRED_SECONDS:EnumProperty.DEFAULT_EXPIRED_SECONDS);

            // 生成cookie发送出去
            Cookie cookie = new Cookie(KeyMsg.TOKEN, token);
            cookie.setMaxAge(1800);
            response.addCookie(cookie);
            mv.setViewName("redirect:/index");
            return mv;
        }
        return mv;
    }

    /**
     * 2.1 用户登录页面验证码
     */
    @RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
    public void kaptcha(HttpServletResponse response){
        // 1. 生成验证码中的 文字和图片
        String text = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(text);

        /*
            2. 将验证码文字存入缓存中，用于判断
                    在多线程的条件下，为了确保当前用户使用到的验证码是自己的，使用用户账号作为缓存key值
                    用户账号不可重复
         */
        String uuid = UUID.randomUUID().toString();
        cacheUtils.getLocalCache().put(uuid, text);
        Cookie cookie = new Cookie(KeyMsg.CAPTCHA, uuid);
        cookie.setMaxAge(180);
        response.addCookie(cookie);

        // 3. 将图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            // 使用ImageIO输出图片，指定图片、图片格式、输出流（注：这个输出流不用关闭。因为整个response是由SpringMVC维护，它自动会关闭。）
            ImageIO.write(image, KeyMsg.PNG_PICTURE, os);
        } catch (IOException e) {
            // 异常需要记录日志信息。。。
            logger.error(PointMsg.login.VERIFY_CODE_OUTPUT_FAIL + e.getMessage());
        }
    }

    /**
     * 用户退出登录
     */
    @RequestMapping(value = "/myLogout")
    public ModelAndView logout(HttpServletResponse response, String path){
        ModelAndView modelAndView = new ModelAndView();
        // 再次发送cookie，覆盖原有的值
        Cookie cookie = new Cookie(KeyMsg.TOKEN, PointMsg.login.LOGIN_OUT);
        cookie.setMaxAge(0);
        response.addCookie(cookie);
        modelAndView.setViewName("redirect:" + path);
        return modelAndView;
    }

    /**
     * 在忘记密码页面验证用户输入的验证码是否正确
     */
    @RequestMapping("/checkEmailCode")
    public ResultData checkEmailCode(String email, String code){
        String emailCode = cacheUtils.getLocalCache().getIfPresent(email);
        if(!code.equals(emailCode)){
            return new ResultData(ResultData.OPERATION_FAIL, PointMsg.register.ERROR_EMAIL_CODE);
        }
        return new ResultData(ResultData.OPERATION_SUCCESS, PointMsg.operation.OPERATION_SUCCESS);
    }

    /**
     * 在忘记密码页面设置新密码（根据邮箱修改用户密码）
     */
    @RequestMapping("/updateForgotPassword")
    public ResultData updateForgotPassword(String email, String password){
        User user = userService.findUserByEmail(email);
        if(user.getPassword().equals(password)){
            return new ResultData(ResultData.OPERATION_FAIL, PointMsg.password.SAME_PASSWORD);
        }
        Integer result = userService.updatePasswordByEmail(email, password);
        if(result > 0){
            return new ResultData(ResultData.OPERATION_SUCCESS, PointMsg.password.UPDATE_PASSWORD_SUCCESS);
        }
        return new ResultData(ResultData.OPERATION_FAIL, PointMsg.password.UPDATE_PASSWORD_FAIL);
    }

}
